package com.qubuyer.customview

import android.animation.ValueAnimator
import android.content.Context
import android.graphics.*
import android.os.Build
import android.util.*
import android.view.View
import android.view.animation.LinearInterpolator
import androidx.annotation.RequiresApi
import androidx.core.util.forEach
import com.qubuyer.R
import java.text.DecimalFormat

/**
 * Created by Allen on 2017/5/14.
 *
 *
 * 自定义水平进度条
 */
open class RebateOrderDetailHorizontalProgressBar @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {

    private var bgPaint: Paint
    private var progressPaint: Paint
    private var tipPaint: Paint
    private var labelPaint: Paint
    private var textPaint: Paint
    private var mWidth = 0
    private var mHeight = 0
    private var mViewHeight = 0

    /**
     * 进度
     */
    private var mProgress = 0f

    /**
     * 当前进度
     */
    private var currentProgress = 0f

    /**
     * 进度动画
     */
    private var progressAnimator: ValueAnimator? = null

    /**
     * 动画执行时间
     */
    private val animDuration = 1000L

    /**
     * 动画延时启动时间
     */
    private val animStartDelay = 500L

    /**
     * 进度条画笔的宽度
     */
    private var progressPaintWidth = 0

    /**
     * 百分比提示框画笔的宽度
     */
    private var tipPaintWidth = 0

    /**
     * 百分比提示框的高度
     */
    private var tipHeight = 0

    /**
     * 百分比提示框的宽度
     */
    private var tipWidth = 0

    /**
     * 画三角形的path
     */
    private val path = Path()

    /**
     * 三角形的高
     */
    private var triangleHeight = 0

    /**
     * 进度条距离提示框的高度
     */
    private var progressMarginTop = 0

    /**
     * 进度移动的距离
     */
    private var moveDis = 0f
    private val textRect = Rect()
    private var textString = "0"

    /**
     * 百分比文字字体大小
     */
    private var textPaintSize = 0

    /**
     * 进度条背景颜色
     */
    private val bgColor = -0x29292a

    /**
     * 进度条颜色
     */
    private val progressColor = -0x6ccd

    /**
     * 绘制提示框的矩形
     */
    private val rectF = RectF()

    /**
     * 圆角矩形的圆角半径
     */
    private var roundRectRadius = 0

    /**
     * 进度监听回调
     */
    private var progressListener: ProgressListener? = null

    private val textAtProgress = SparseArray<String>()

    /**
     * 初始化画笔宽度及view大小
     */
    init {
        val a0 = context.obtainStyledAttributes(
            attrs,
            R.styleable.RebateOrderDetailHorizontalProgressBar,
            defStyleAttr,
            0
        )
        var string =
            a0.getString(R.styleable.RebateOrderDetailHorizontalProgressBar_textAtProgress)
        a0.recycle()
        if (isInEditMode) {
            if (string == null) {
                string = "1月@33|2月@67|3月@100"
            }
        }
        string?.apply {
            if (this.isEmpty()) {
                return@apply
            }
            val arr = split("|")
            arr.forEach {
                try {
                    val kv = it.split("@")
                    val text = kv[0]
                    val progress = kv[1].toInt()
                    textAtProgress.put(progress, text)
                } catch (e: Exception) {

                }
            }
        }

        progressPaintWidth = dp2px(7)
        tipHeight = dp2px(19)
        tipWidth = dp2px(44)
        tipPaintWidth = dp2px(1)
        triangleHeight = dp2px(4)
        roundRectRadius = dp2px(1)
        textPaintSize = sp2px(9)
        progressMarginTop = dp2px(9)
        //view真实的高度
        mViewHeight =
            tipHeight + tipPaintWidth + triangleHeight + progressPaintWidth + progressMarginTop
        if (textAtProgress.size() > 0) {
            mViewHeight += sp2px(10)
        }
        bgPaint = getPaint(progressPaintWidth, bgColor, Paint.Style.STROKE)
        progressPaint = getPaint(progressPaintWidth, progressColor, Paint.Style.STROKE)
        tipPaint = getPaint(tipPaintWidth, progressColor, Paint.Style.FILL)
        labelPaint = Paint().apply {
            color = Color.parseColor("#999999")
            textSize = sp2px(10).toFloat()
            isAntiAlias = true
            isDither = true
        }
        textPaint = Paint(Paint.ANTI_ALIAS_FLAG)
        textPaint.textSize = textPaintSize.toFloat()
        textPaint.color = Color.WHITE
        textPaint.textAlign = Paint.Align.CENTER
        textPaint.isAntiAlias = true
    }

    /**
     * 统一处理paint
     *
     * @param strokeWidth
     * @param color
     * @param style
     * @return
     */
    private fun getPaint(strokeWidth: Int, color: Int, style: Paint.Style): Paint {
        val paint = Paint(Paint.ANTI_ALIAS_FLAG)
        paint.strokeWidth = strokeWidth.toFloat()
        paint.color = color
        paint.isAntiAlias = true
        paint.strokeCap = Paint.Cap.ROUND
        paint.style = style
        return paint
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        val widthMode = MeasureSpec.getMode(widthMeasureSpec)
        val width = MeasureSpec.getSize(widthMeasureSpec)
        val heightMode = MeasureSpec.getMode(heightMeasureSpec)
        val height = MeasureSpec.getSize(heightMeasureSpec)
        setMeasuredDimension(measureWidth(widthMode, width), measureHeight(heightMode, height))
    }

    /**
     * 测量宽度
     *
     * @param mode
     * @param width
     * @return
     */
    private fun measureWidth(mode: Int, width: Int): Int {
        when (mode) {
            MeasureSpec.UNSPECIFIED, MeasureSpec.AT_MOST -> {
            }
            MeasureSpec.EXACTLY -> mWidth = width
        }
        return mWidth
    }

    /**
     * 测量高度
     *
     * @param mode
     * @param height
     * @return
     */
    private fun measureHeight(mode: Int, height: Int): Int {
        when (mode) {
            MeasureSpec.UNSPECIFIED, MeasureSpec.AT_MOST -> mHeight = mViewHeight
            MeasureSpec.EXACTLY -> mHeight = height
        }
        return mHeight
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        val offset = tipWidth / 2
        bgPaint.strokeCap = Paint.Cap.ROUND
        canvas.drawLine(
            paddingLeft.toFloat() + offset, (
                    tipHeight + progressMarginTop).toFloat(),
            width.toFloat() - offset - paddingRight, (
                    tipHeight + progressMarginTop).toFloat(),
            bgPaint
        )

        canvas.drawLine(
            paddingLeft.toFloat() + offset, (
                    tipHeight + progressMarginTop).toFloat(),
            paddingLeft.toFloat() + offset + currentProgress, (
                    tipHeight + progressMarginTop).toFloat(),
            progressPaint
        )

        drawTipView(canvas)
        drawText(canvas, textString)
        drawLabel(canvas)
    }

    private fun drawLabel(canvas: Canvas) {
        if (textAtProgress.size() == 0) {
            return
        }
        textAtProgress.forEach { key, value ->
            val textWidth = labelPaint.measureText(value)
            val fontMetrics = labelPaint.fontMetricsInt
            val baseline = mHeight - sp2px(10) +
                    (fontMetrics.bottom - fontMetrics.top) / 2 - fontMetrics.bottom
            //文字绘制到整个布局的中心位置
            canvas.drawText(
                value,
                tipWidth / 2 + key * (mWidth - tipWidth) / 100 - textWidth / 2,
                baseline.toFloat(),
                labelPaint
            )
        }
    }

    /**
     * 绘制进度上边提示百分比的view
     *
     * @param canvas
     */
    private fun drawTipView(canvas: Canvas) {
        drawRoundRect(canvas)
        drawTriangle(canvas)
    }

    /**
     * 绘制圆角矩形
     *
     * @param canvas
     */
    private fun drawRoundRect(canvas: Canvas) {
        rectF[moveDis, 0f, tipWidth + moveDis] = tipHeight.toFloat()
        canvas.drawRoundRect(
            rectF,
            roundRectRadius.toFloat(),
            roundRectRadius.toFloat(),
            tipPaint
        )
    }

    /**
     * 绘制三角形
     *
     * @param canvas
     */
    private fun drawTriangle(canvas: Canvas) {
        path.moveTo(tipWidth / 2 - triangleHeight + moveDis, tipHeight.toFloat())
        path.lineTo(tipWidth / 2 + moveDis, (tipHeight + triangleHeight).toFloat())
        path.lineTo(tipWidth / 2 + triangleHeight + moveDis, tipHeight.toFloat())
        canvas.drawPath(path, tipPaint)
        path.reset()
    }

    /**
     * 绘制文字
     *
     * @param canvas 画布
     */
    private fun drawText(canvas: Canvas, textString: String) {
        textRect.left = moveDis.toInt()
        textRect.top = 0
        textRect.right = (tipWidth + moveDis).toInt()
        textRect.bottom = tipHeight
        val fontMetrics = textPaint.fontMetricsInt
        val baseline = (textRect.bottom + textRect.top - fontMetrics.bottom - fontMetrics.top) / 2
        //文字绘制到整个布局的中心位置
        canvas.drawText(
            "折让$textString%",
            textRect.centerX().toFloat(),
            baseline.toFloat(),
            textPaint
        )
    }

    /**
     * 进度移动动画  通过插值的方式改变移动的距离
     */
    private fun initAnimation() {
        progressAnimator = ValueAnimator.ofFloat(0f, mProgress).apply {
            duration = animDuration
            startDelay = animStartDelay
            interpolator = LinearInterpolator()
            addUpdateListener { valueAnimator ->
                val value = valueAnimator.animatedValue as Float
                //进度数值只显示整数，我们自己的需求，可以忽略
//                textString = formatNum(format2Int(value));
                //把当前百分比进度转化成view宽度对应的比例
                currentProgress = value * (mWidth - tipWidth) / 100
                //进度回调方法
                progressListener?.currentProgressListener(value)
                //移动百分比提示框，只有当前进度到提示框中间位置之后开始移动，
                //当进度框移动到最右边的时候停止移动，但是进度条还可以继续移动
                //moveDis是tip框移动的距离
//                if (currentProgress >= tipWidth / 2 &&
//                    currentProgress <= mWidth - tipWidth / 2
//                ) {
//                    moveDis = currentProgress - tipWidth / 2
//                }
                Log.e("Rebate", "w=${mWidth}  progress=${currentProgress}")
                moveDis = currentProgress
                invalidate()
            }
            start()
        }
    }

    /**
     * 设置进度条带动画效果
     *
     * @param progress
     * @return
     */
    fun setProgressWithAnimation(progress: Float): RebateOrderDetailHorizontalProgressBar {
        mProgress = progress.coerceAtMost(100f)
        initAnimation()
        return this
    }

    /**
     * 实时显示进度
     *
     * @param progress
     * @return
     */
    fun setCurrentProgress(progress: Float): RebateOrderDetailHorizontalProgressBar {
        mProgress = progress
        currentProgress = progress * (mWidth - tipWidth) / 100
        textString = formatNum(format2Int(progress.toDouble()))
        invalidate()
        return this
    }

    fun setCurrentProgressText(textString: String): RebateOrderDetailHorizontalProgressBar {
        this.textString = textString
        invalidate()
        return this
    }

    /**
     * 开启动画
     */
    fun startProgressAnimation() {
        if (progressAnimator != null && !progressAnimator!!.isRunning && !progressAnimator!!.isStarted) progressAnimator!!.start()
    }

    /**
     * 暂停动画
     */
    @RequiresApi(api = Build.VERSION_CODES.KITKAT)
    fun pauseProgressAnimation() {
        progressAnimator?.pause()
    }

    /**
     * 恢复动画
     */
    @RequiresApi(api = Build.VERSION_CODES.KITKAT)
    fun resumeProgressAnimation() {
        progressAnimator?.resume()
    }

    /**
     * 停止动画
     */
    fun stopProgressAnimation() {
        progressAnimator?.end()
    }

    /**
     * 回调接口
     */
    interface ProgressListener {
        fun currentProgressListener(currentProgress: Float)
    }

    /**
     * 回调监听事件
     *
     * @param listener
     * @return
     */
    fun setProgressListener(listener: ProgressListener?): RebateOrderDetailHorizontalProgressBar {
        progressListener = listener
        return this
    }

    /**
     * dp 2 px
     *
     * @param dpVal
     */
    protected fun dp2px(dpVal: Int): Int {
        return TypedValue.applyDimension(
            TypedValue.COMPLEX_UNIT_DIP,
            dpVal.toFloat(), resources.displayMetrics
        ).toInt()
    }

    /**
     * sp 2 px
     *
     * @param spVal
     * @return
     */
    protected fun sp2px(spVal: Int): Int {
        return TypedValue.applyDimension(
            TypedValue.COMPLEX_UNIT_SP,
            spVal.toFloat(), resources.displayMetrics
        ).toInt()
    }

    companion object {
        /**
         * 格式化数字(保留两位小数)
         *
         * @param money
         * @return
         */
        fun formatNumTwo(money: Double): String {
            val format = DecimalFormat("0.00")
            return format.format(money)
        }

        /**
         * 格式化数字(保留一位小数)
         *
         * @param money
         * @return
         */
        fun formatNum(money: Int): String {
            val format = DecimalFormat("0")
            return format.format(money.toLong())
        }

        fun format2Int(i: Double): Int {
            return i.toInt()
        }
    }
}